﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OpGen.Compiler
{
    /// <summary>
    /// Element Typen
    /// </summary>
    [Serializable]
    public enum ElementTypeEnum
    {
        /// <summary>
        /// Namespace
        /// </summary>
        Namespace,

        /// <summary>
        /// Klasse
        /// </summary>
        Class,

        /// <summary>
        /// Message
        /// </summary>
        Message,

        /// <summary>
        /// Auflistung
        /// </summary>
        Enum,

        /// <summary>
        /// Auflistungsteil
        /// </summary>
        EnumItem,

        /// <summary>
        /// Feld
        /// </summary>
        Field,

        /// <summary>
        /// Listenfeld
        /// </summary>
        ListField,

        /// <summary>
        /// Projekt
        /// </summary>
        Project
    }

    /// <summary>
    /// Modifizierer Typen
    /// </summary>
    [Serializable]
    public enum ModifierEnum
    {
        /// <summary>
        /// Keine Angabe
        /// </summary>
        None,

        /// <summary>
        /// Unbekannt
        /// </summary>
        Unkown,

        /// <summary>
        /// Privat
        /// </summary>
        Private,

        /// <summary>
        /// Öffentlich
        /// </summary>
        Public,

        /// <summary>
        /// Intern
        /// </summary>
        Internal,

        /// <summary>
        /// Geschützt
        /// </summary>
        Protected
    }

    /// <summary>
    /// Stellt ein Element mit Basisfunktionen dar
    /// </summary>
    [Serializable]
    public abstract class OpGenElement
    {
        private ElementCollection _ChildElements = new ElementCollection();

        /// <summary>
        /// Erstellt eine neue Instanz der BaseElement-Klasse
        /// </summary>
        /// <param name="ParentElement"></param>
        /// <param name="ElementType"></param>
        protected OpGenElement(OpGenElement ParentElement, ElementTypeEnum ElementType)
        {
            this.ElementType = ElementType;
            this.ParentElement = ParentElement;
            this.Elementname = "";

            GetNamespaceElement();
        }

        /// <summary>
        /// Liefert das Eltern Element
        /// </summary>
        public OpGenElement ParentElement { get; private set; }

        /// <summary>
        /// Liefert den Element Typ
        /// </summary>
        public ElementTypeEnum ElementType { get; private set; }

        /// <summary>
        /// Liefert den Modifizierer
        /// </summary>
        public ModifierEnum Modifier { get; set; }

        /// <summary>
        /// Liefert den Datentyp
        /// </summary>
        public OpGenTypeInfo Type { get; internal set; }

        /// <summary>
        /// Liefert den Elementnamen oder legt ihn fest
        /// </summary>
        public string Elementname { get; set; }

        //public int Position { get; set; }
        //public int Length { get; set; }

        /// <summary>
        /// Liefert den Namespace in dem es enthalten ist
        /// </summary>
        public OpGenNamespace Namespace { get; private set; }

        /// <summary>
        /// Liefert den Kompletten Typenamen inklusive Namespace
        /// </summary>
        public string Fullname
        {
            get
            {
                if (Namespace == null)
                    return Elementname;
                else
                    return Namespace.Elementname + "." + Elementname;
            }
        }

        /// <summary>
        /// Gibt das Projekt-Element zurück
        /// </summary>
        /// <returns></returns>
        public OpGenProject GetProjectElement()
        {
            if (ParentElement == null)
                return (OpGenProject)this;

            var Element = this.ParentElement;

            while (Element.ParentElement != null)
            {
                Element = Element.ParentElement;
            }

            return (OpGenProject)Element;
        }

        /// <summary>
        /// Liefert das Namespace Element zurück, in dem dieses Element enthalten ist
        /// </summary>
        private void GetNamespaceElement()
        {
            var Element = this.ParentElement;

            if (Element == null)
                return;

            if (Element is OpGenProject)
            {
                Namespace = (OpGenNamespace)this;
                return;
            }

            while ((Element.ParentElement is OpGenNamespace))
            {
                Element = Element.ParentElement;
            }

            Namespace = (OpGenNamespace)Element;
        }

        /// <summary>
        /// Liefert eine Liste mit Unterelementen
        /// </summary>
        public ElementCollection ChildElements
        {
            get { return _ChildElements; }
        }

        /// <summary>
        ///  Liefert die Textbezeichnung des Elements
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("{0} {1} {2}", Modifier.ToString(), ElementType.ToString(), Elementname); 
        }
    }
}
